// 版权所有2012 Go作者。保留所有权利。
// 此源代码的使用受BSD样式
// 许可证的约束，该许可证可以在许可证文件中找到。

// 此文件实现表达式的类型检查。

package types

import (
	"fmt"
	"go/ast"
	"go/constant"
	"go/internal/typeparams"
	"go/token"
	"math"
)

/*
Basic algorithm:

Expressions are checked recursively, top down. Expression checker functions
are generally of the form:

  func f(x *operand, e *ast.Expr, ...)

where e is the expression to be checked, and x is the result of the check.
The check performed by f may fail in which case x.mode == invalid, and
related error messages will have been issued by f.

If a hint argument is present, it is the composite literal element type
of an outer composite literal; it is used to type-check composite literal
elements that have no explicit type specification in the source
(e.g.: []T{{...}, {...}}, the hint is the type T in this case).

All expressions are checked via rawExpr, which dispatches according
to expression kind. Upon returning, rawExpr is recording the types and
constant values for all expressions that have an untyped type (those types
may change on the way up in the expression tree). Usually these are constants,
but the results of comparisons or non-constant shifts of untyped constants
may also be untyped, but not constant.

Untyped expressions may eventually become fully typed (i.e., not untyped),
typically when the value is assigned to a variable, or is used otherwise.
The updateExprType method is used to record this final type and update
the recorded types: the type-checked expression tree is again traversed down,
and the new type is propagated as needed. Untyped constant expression values
that become fully typed must now be representable by the full type (constant
sub-expression trees are left alone except for their roots). This mechanism
ensures that a client sees the actual (run-time) type an untyped value would
have. It also permits type-checking of lhs shift operands "as if the shift
were not present": when updateExprType visits an untyped lhs shift operand
and assigns it it's final type, that type must be an integer type, and a
constant lhs must be representable as an integer.

When an expression gets its final type, either on the way out from rawExpr,
on the way down in updateExprType, or at the end of the type checker run,
the type (and constant value, if any) is recorded via Info.Types, if present.
*/

type opPredicates map[token.Token]func(Type) bool

var unaryOpPredicates opPredicates

func init() {
	// 在init中设置unaryOpPredicates可以避免声明周期。
	unaryOpPredicates = opPredicates{
		token.ADD: allNumeric,
		token.SUB: allNumeric,
		token.XOR: allInteger,
		token.NOT: allBoolean,
	}
}

func (check *Checker) op(m opPredicates, x *operand, op token.Token) bool {
	if pred := m[op]; pred != nil {
		if !pred(x.typ) {
			check.invalidOp(x, _UndefinedOp, "operator %s not defined on %s", op, x)
			return false
		}
	} else {
		check.invalidAST(x, "unknown operator %s", op)
		return false
	}
	return true
}

// 溢出检查常量x是否可以通过其类型表示。
// 对于非类型化常量，它会检查值是否变为任意大。
func (check *Checker) overflow(x *operand, op token.Token, opPos token.Pos) {
	assert(x.mode == constant_)

	if x.val.Kind() == constant.Unknown {
		// TODO（gri）我们应该准确报告出了什么问题。目前我们还没有（go/constant）API来实现这一点。
		// 另请参见go/constant/value中的TODO。去
		check.errorf(atPos(opPos), _InvalidConstVal, "constant result is not representable")
		return
	}

	// 类型化常量必须在
	// 中表示，在每次常量操作之后，它们的类型都必须是可表示的。
	// x.typ不能是类型参数（类型
	// 参数不能是常量类型）。
	if isTyped(x.typ) {
		check.representable(x, under(x.typ).(*Basic))
		return
	}

	// 非类型化整数值不能任意增长。
	const prec = 512 // 512是常量精度
	if x.val.Kind() == constant.Int && constant.BitLen(x.val) > prec {
		check.errorf(atPos(opPos), _InvalidConstVal, "constant %s overflow", opName(x.expr))
		x.val = constant.MakeUnknown()
	}
}

// opName返回操作的名称或空字符串。
// 只处理可能溢出的操作。
func opName(e ast.Expr) string {
	switch e := e.(type) {
	case *ast.BinaryExpr:
		if int(e.Op) < len(op2str2) {
			return op2str2[e.Op]
		}
	case *ast.UnaryExpr:
		if int(e.Op) < len(op2str1) {
			return op2str1[e.Op]
		}
	}
	return ""
}

var op2str1 = [...]string{
	token.XOR: "bitwise complement",
}

// 这仅用于可能导致溢出的操作。
var op2str2 = [...]string{
	token.ADD: "addition",
	token.SUB: "subtraction",
	token.XOR: "bitwise XOR",
	token.MUL: "multiplication",
	token.SHL: "shift",
}

// 如果typ是一个类型参数，underIs将返回typ的结果。underIs（f）。
// 否则，underIs返回f（在（typ）下）的结果。
func underIs(typ Type, f func(Type) bool) bool {
	if tpar, _ := typ.(*TypeParam); tpar != nil {
		return tpar.underIs(f)
	}
	return f(under(typ))
}

// 一元表达式e可以是零。它只是为了更好的错误信息而传入的。
func (check *Checker) unary(x *operand, e *ast.UnaryExpr) {
	check.expr(x, e.X)
	if x.mode == invalid {
		return
	}
	switch e.Op {
	case token.AND:
		// 规范：“作为可寻址
		// 的例外，要求x也可以是复合文字。”
		if _, ok := unparen(e.X).(*ast.CompositeLit); !ok && x.mode != variable {
			check.invalidOp(x, _UnaddressableOperand, "cannot take address of %s", x)
			x.mode = invalid
			return
		}
		x.mode = value
		x.typ = &Pointer{base: x.typ}
		return

	case token.ARROW:
		u := coreType(x.typ)
		if u == nil {
			check.invalidOp(x, _InvalidReceive, "cannot receive from %s: no core type", x)
			x.mode = invalid
			return
		}
		ch, _ := u.(*Chan)
		if ch == nil {
			check.invalidOp(x, _InvalidReceive, "cannot receive from non-channel %s", x)
			x.mode = invalid
			return
		}
		if ch.dir == SendOnly {
			check.invalidOp(x, _InvalidReceive, "cannot receive from send-only channel %s", x)
			x.mode = invalid
			return
		}

		x.mode = commaok
		x.typ = ch.elem
		check.hasCallOrRecv = true
		return
	}

	if !check.op(unaryOpPredicates, x, e.Op) {
		x.mode = invalid
		return
	}

	if x.mode == constant_ {
		if x.val.Kind() == constant.Unknown {
			// 什么也不做（并且不要在下面的溢出检查中导致错误）
			return
		}
		var prec uint
		if isUnsigned(x.typ) {
			prec = uint(check.conf.sizeof(x.typ) * 8)
		}
		x.val = constant.UnaryOp(e.Op, x.val, prec)
		x.expr = e
		check.overflow(x, e.Op, x.Pos())
		return
	}

	x.mode = value
	// x.typ保持不变
}

func isShift(op token.Token) bool {
	return op == token.SHL || op == token.SHR
}

func isComparison(op token.Token) bool {
	// 注意：令牌的顺序不是为了让这更简单
	switch op {
	case token.EQL, token.NEQ, token.LSS, token.LEQ, token.GTR, token.GEQ:
		return true
	}
	return false
}

func fitsFloat32(x constant.Value) bool {
	f32, _ := constant.Float32Val(x)
	f := float64(f32)
	return !math.IsInf(f, 0)
}

func roundFloat32(x constant.Value) constant.Value {
	f32, _ := constant.Float32Val(x)
	f := float64(f32)
	if !math.IsInf(f, 0) {
		return constant.MakeFloat64(f)
	}
	return nil
}

func fitsFloat64(x constant.Value) bool {
	f, _ := constant.Float64Val(x)
	return !math.IsInf(f, 0)
}

func roundFloat64(x constant.Value) constant.Value {
	f, _ := constant.Float64Val(x)
	if !math.IsInf(f, 0) {
		return constant.MakeFloat64(f)
	}
	return nil
}

// representableConst报告x是否可以表示为
// 给定基本类型和配置的值
// 提供（仅适用于int/uint尺寸）。
// 
// 如果四舍五入！=nil，*rounded对于
// 可表示的浮点值和复数值设置为x的舍入值，对于整数值设置为Int 
// 值；否则就别管它了。
// 可以提供四舍五入的第一个参数的地址。
// 
// 如果通过导出的API调用（可分配到，可转换到）
// （间接），则check参数可能为零，因为这些调用不需要检查程序的配置。
// 调用representableConst 
func representableConst(x constant.Value, check *Checker, typ *Basic, rounded *constant.Value) bool {
	if x.Kind() == constant.Unknown {
		return true // 避免后续错误
	}

	var conf *Config
	if check != nil {
		conf = check.conf
	}

	switch {
	case isInteger(typ):
		x := constant.ToInt(x)
		if x.Kind() != constant.Int {
			return false
		}
		if rounded != nil {
			*rounded = x
		}
		if x, ok := constant.Int64Val(x); ok {
			switch typ.kind {
			case Int:
				var s = uint(conf.sizeof(typ)) * 8
				return int64(-1)<<(s-1) <= x && x <= int64(1)<<(s-1)-1
			case Int8:
				const s = 8
				return -1<<(s-1) <= x && x <= 1<<(s-1)-1
			case Int16:
				const s = 16
				return -1<<(s-1) <= x && x <= 1<<(s-1)-1
			case Int32:
				const s = 32
				return -1<<(s-1) <= x && x <= 1<<(s-1)-1
			case Int64, UntypedInt:
				return true
			case Uint, Uintptr:
				if s := uint(conf.sizeof(typ)) * 8; s < 64 {
					return 0 <= x && x <= int64(1)<<s-1
				}
				return 0 <= x
			case Uint8:
				const s = 8
				return 0 <= x && x <= 1<<s-1
			case Uint16:
				const s = 16
				return 0 <= x && x <= 1<<s-1
			case Uint32:
				const s = 32
				return 0 <= x && x <= 1<<s-1
			case Uint64:
				return 0 <= x
			default:
				unreachable()
			}
		}
		// x不适合int64 
		switch n := constant.BitLen(x); typ.kind {
		case Uint, Uintptr:
			var s = uint(conf.sizeof(typ)) * 8
			return constant.Sign(x) >= 0 && n <= int(s)
		case Uint64:
			return constant.Sign(x) >= 0 && n <= 64
		case UntypedInt:
			return true
		}

	case isFloat(typ):
		x := constant.ToFloat(x)
		if x.Kind() != constant.Float {
			return false
		}
		switch typ.kind {
		case Float32:
			if rounded == nil {
				return fitsFloat32(x)
			}
			r := roundFloat32(x)
			if r != nil {
				*rounded = r
				return true
			}
		case Float64:
			if rounded == nil {
				return fitsFloat64(x)
			}
			r := roundFloat64(x)
			if r != nil {
				*rounded = r
				return true
			}
		case UntypedFloat:
			return true
		default:
			unreachable()
		}

	case isComplex(typ):
		x := constant.ToComplex(x)
		if x.Kind() != constant.Complex {
			return false
		}
		switch typ.kind {
		case Complex64:
			if rounded == nil {
				return fitsFloat32(constant.Real(x)) && fitsFloat32(constant.Imag(x))
			}
			re := roundFloat32(constant.Real(x))
			im := roundFloat32(constant.Imag(x))
			if re != nil && im != nil {
				*rounded = constant.BinaryOp(re, token.ADD, constant.MakeImag(im))
				return true
			}
		case Complex128:
			if rounded == nil {
				return fitsFloat64(constant.Real(x)) && fitsFloat64(constant.Imag(x))
			}
			re := roundFloat64(constant.Real(x))
			im := roundFloat64(constant.Imag(x))
			if re != nil && im != nil {
				*rounded = constant.BinaryOp(re, token.ADD, constant.MakeImag(im))
				return true
			}
		case UntypedComplex:
			return true
		default:
			unreachable()
		}

	case isString(typ):
		return x.Kind() == constant.String

	case isBoolean(typ):
		return x.Kind() == constant.Bool
	}

	return false
}

// 可表示性检查常量操作数在给定
// 基本类型中是否可表示。
func (check *Checker) representable(x *operand, typ *Basic) {
	v, code := check.representation(x, typ)
	if code != 0 {
		check.invalidConversion(code, x, typ)
		x.mode = invalid
		return
	}
	assert(v != nil)
	x.val = v
}

// 表示返回常量操作数x作为
// 基本类型的表示。
// 
// 如果无法进行此类表示，则返回非零错误代码。
func (check *Checker) representation(x *operand, typ *Basic) (constant.Value, errorCode) {
	assert(x.mode == constant_)
	v := x.val
	if !representableConst(x.val, check, typ, &v) {
		if isNumeric(x.typ) && isNumeric(typ) {
			// 数值转换：错误消息
			// 
			// 整数->整数：溢出
			// 整数->浮点：溢出（实际上不可能）
			// 浮点->整数：截断
			// 浮点->浮点：溢出
			// 
			if !isInteger(x.typ) && isInteger(typ) {
				return nil, _TruncatedFloat
			} else {
				return nil, _NumericOverflow
			}
		}
		return nil, _InvalidConstVal
	}
	return v, 0
}

func (check *Checker) invalidConversion(code errorCode, x *operand, target Type) {
	msg := "cannot convert %s to %s"
	switch code {
	case _TruncatedFloat:
		msg = "%s truncated to %s"
	case _NumericOverflow:
		msg = "%s overflows %s"
	}
	check.errorf(x, code, msg, x, target)
}

// updateExprType将x的类型更新为typ并根据表达式类型，对x的操作数递归调用
// 自身。
// 如果typ仍然是非类型化的，而不是最终类型，则updateExprType 
// 只更新记录的x的非类型化类型，可能还更新其
// 操作数。否则（即typ不再是非类型类型，
// 或它是x的最终类型），将记录类型和值。
// 另外，如果x是常数，它必须表示为typ，
// 的值，如果x是非常数
// 移位的（以前未类型化）lhs操作数，它必须是整数值。
func (check *Checker) updateExprType(x ast.Expr, typ Type, final bool) {
	check.updateExprType0(nil, x, typ, final)
}

func (check *Checker) updateExprType0(parent, x ast.Expr, typ Type, final bool) {
	old, found := check.untyped[x]
	if !found {
		return // 无需操作
	}

	// 必要时更新x的操作数
	switch x := x.(type) {
	case *ast.BadExpr,
		*ast.FuncLit,
		*ast.CompositeLit,
		*ast.IndexExpr,
		*ast.SliceExpr,
		*ast.TypeAssertExpr,
		*ast.StarExpr,
		*ast.KeyValueExpr,
		*ast.ArrayType,
		*ast.StructType,
		*ast.FuncType,
		*ast.InterfaceType,
		*ast.MapType,
		*ast.ChanType:
		// 这些表达式从来都不是非类型化的-无需操作。
		// 在赋值或使用时，相应的子表达式得到了它们的最终类型
		// 。
		if debug {
			check.dump("%v: found old type(%s): %s (new: %s)", x.Pos(), x, old.typ, typ)
			unreachable()
		}
		return

	case *ast.CallExpr:
		// 导致一个非类型化常数（例如，内置复合体）。
		// 如果需要，相应的调用将负责调用updateExprType 
		// 以获取参数。

	case *ast.Ident, *ast.BasicLit, *ast.SelectorExpr:
		// 表示常量、常量文字、
		// 或限定标识符（导入的非类型化常量）的标识符。
		// 没有要处理的操作数。

	case *ast.ParenExpr:
		check.updateExprType0(x, x.X, typ, final)

	case *ast.UnaryExpr:
		// 如果x是常数，则操作数是常数。
		// 操作数不需要更新，因为它们永远不会“物化”为类型化值。如果
		// 留在非类型映射中，则将在类型检查结束时对其进行处理。
		if old.val != nil {
			break
		}
		check.updateExprType0(x, x.X, typ, final)

	case *ast.BinaryExpr:
		if old.val != nil {
			break // 一元表达式请参见注释
		}
		if isComparison(x.Op) {
			// 结果类型独立于操作数类型
			// 并且操作数类型必须具有final类型。
		} else if isShift(x.Op) {
			// 结果类型仅取决于lhs操作数。
			// 检查班次时，rhs类型已更新。
			check.updateExprType0(x, x.X, typ, final)
		} else {
			// 操作数类型与结果类型匹配。
			check.updateExprType0(x, x.X, typ, final)
			check.updateExprType0(x, x.Y, typ, final)
		}

	default:
		unreachable()
	}

	// 如果新类型不是最终类型，仍然没有类型，只需
	// 更新记录的类型即可。
	if !final && isUntyped(typ) {
		old.typ = under(typ).(*Basic)
		check.untyped[x] = old
		return
	}

	// 否则我们就有了最终的（类型化或非类型化的类型）。
	// 将其从尚未类型化的表达式映射中删除。
	delete(check.untyped, x)

	if old.isLhs {
		// 如果x是移位的lhs，则其最终类型必须为整数。
		// 我们已经从移位检查中知道，如果它是一个常数，它可以表示为一个整数。
		if !allInteger(typ) {
			if compilerErrorMessages {
				check.invalidOp(x, _InvalidShiftOperand, "%s (shift of type %s)", parent, typ)
			} else {
				check.invalidOp(x, _InvalidShiftOperand, "shifted operand %s (type %s) must be integer", x, typ)
			}
			return
		}
		// 即使我们有一个整数，如果这个值是常数，我们
		// 仍然必须检查它是否可以表示为请求的特定
		// int类型（was问题#22969）。从这里掉下去。
	}
	if old.val != nil {
		// 如果x是一个常数，它必须表示为一个典型值。
		c := operand{old.mode, x, old.typ, old.val, 0}
		check.convertUntyped(&c, typ)
		if c.mode == invalid {
			return
		}
	}

	// 一切正常，记录x的最终类型和值。
	check.recordTypeAndValue(x, old.mode, typ, old.val)
}

// updateExprVal将x的值更新为val。
func (check *Checker) updateExprVal(x ast.Expr, val constant.Value) {
	if info, ok := check.untyped[x]; ok {
		info.val = val
		check.untyped[x] = info
	}
}

// convertUntyped尝试将非类型化值的类型设置为目标类型。
func (check *Checker) convertUntyped(x *operand, target Type) {
	newType, val, code := check.implicitTypeAndValue(x, target)
	if code != 0 {
		t := target
		if !isTypeParam(target) {
			t = safeUnderlying(target)
		}
		check.invalidConversion(code, x, t)
		x.mode = invalid
		return
	}
	if val != nil {
		x.val = val
		check.updateExprVal(x.expr, val)
	}
	if newType != x.typ {
		x.typ = newType
		check.updateExprType(x.expr, newType, false)
	}
}

// implicitTypeAndValue在预期目标类型的上下文
// 中使用时，返回x的隐式类型。如果没有这样的隐式转换
// 可能，它将返回一个nil类型和非零错误代码。
// 
// 如果x是常量操作数，则返回常量。值将是
// 在此上下文中x的表示形式。
func (check *Checker) implicitTypeAndValue(x *operand, target Type) (Type, constant.Value, errorCode) {
	if x.mode == invalid || isTyped(x.typ) || target == Typ[Invalid] {
		return x.typ, nil, 0
	}

	if isUntyped(target) {
		// x和target都是非类型化
		xkind := x.typ.(*Basic).kind
		tkind := target.(*Basic).kind
		if isNumeric(x.typ) && isNumeric(target) {
			if xkind < tkind {
				return target, nil, 0
			}
		} else if xkind != tkind {
			return nil, nil, _InvalidUntypedConversion
		}
		return x.typ, nil, 0
	}

	switch u := under(target).(type) {
	case *Basic:
		if x.mode == constant_ {
			v, code := check.representation(x, u)
			if code != 0 {
				return nil, nil, code
			}
			return target, v, code
		}
		// 非常量非类型化值可能显示为
		// 比较结果（非类型化bool）、中间
		// （延迟检查）rhs移位操作数，以及
		// 值nil。
		switch x.typ.(*Basic).kind {
		case UntypedBool:
			if !isBoolean(target) {
				return nil, nil, _InvalidUntypedConversion
			}
		case UntypedInt, UntypedRune, UntypedFloat, UntypedComplex:
			if !isNumeric(target) {
				return nil, nil, _InvalidUntypedConversion
			}
		case UntypedString:
			// 规范不允许非常量非类型化字符串值，并且
			// 在正常的类型检查过程中不应出现，但此路径是
			// 可通过AssignableTo API访问的。
			if !isString(target) {
				return nil, nil, _InvalidUntypedConversion
			}
		case UntypedNil:
			// 不安全。指针是包含nil的基本类型。
			if !hasNil(target) {
				return nil, nil, _InvalidUntypedConversion
			}
			// 将nil的类型保留为UntypedNil：参见#13061。
			return Typ[UntypedNil], nil, 0
		default:
			return nil, nil, _InvalidUntypedConversion
		}
	case *Interface:
		if isTypeParam(target) {
			if !u.typeSet().underIs(func(u Type) bool {
				if u == nil {
					return false
				}
				t, _, _ := check.implicitTypeAndValue(x, u)
				return t != nil
			}) {
				return nil, nil, _InvalidUntypedConversion
			}
			// 保持nil非类型化（was bug#39755）
			if x.isNil() {
				return Typ[UntypedNil], nil, 0
			}
			break
		}
		// 值必须具有具体的动态类型。如果值为nil，则保持其非类型化（这对于go vet等工具很重要，因为它需要动态类型来检查参数，例如print 
		// 函数）
		if x.isNil() {
			return Typ[UntypedNil], nil, 0
		}
		// 无法将非类型化的值分配给非空接口
		if !u.Empty() {
			return nil, nil, _InvalidUntypedConversion
		}
		return Default(x.typ), nil, 0
	case *Pointer, *Signature, *Slice, *Map, *Chan:
		if !x.isNil() {
			return nil, nil, _InvalidUntypedConversion
		}
		// 保持nil非类型化-请参阅上面的接口注释。
		return Typ[UntypedNil], nil, 0
	default:
		return nil, nil, _InvalidUntypedConversion
	}
	return target, nil, 0
}

// 如果switchCase为true，则忽略运算符op。
func (check *Checker) comparison(x, y *operand, op token.Token, switchCase bool) {
	if switchCase {
		op = token.EQL
	}

	errOp := x  // 报告错误的操作数，如果有任何
	cause := "" // 特定错误原因，如果有任何

	// 规范：“在任何比较中，第一个操作数必须可分配给第二个操作数的类型，反之亦然。”
	code := _MismatchedTypes
	ok, _ := x.assignableTo(check, y.typ, nil)
	if !ok {
		ok, _ = y.assignableTo(check, x.typ, nil)
	}
	if !ok {
		// 报告第二个操作数上的错误，因为我们只有
		// 在看到第二个操作数后才知道是否存在
		// 类型不匹配。
		errOp = y
		// 目前，如果我们没有运行编译器，请使用x的
		// 位置来最小化对现有测试的更改。
		if !compilerErrorMessages {
			errOp = x
		}
		cause = check.sprintf("mismatched types %s and %s", x.typ, y.typ)
		goto Error
	}

	// 检查是否为操作数定义了比较
	code = _UndefinedOp
	switch op {
	case token.EQL, token.NEQ:
		// 规范：“等式运算符==和！=适用于可比较的操作数。”
		switch {
		case x.isNil() || y.isNil():
			// 与nil进行比较需要另一个操作数类型为nil。
			typ := x.typ
			if x.isNil() {
				typ = y.typ
			}
			if !hasNil(typ) {
				// 这种情况只适用于“nil==nil”。
				// 报告第二个操作数上的错误，因为我们只有
				// 看到第二个操作数后才知道是否有
				// 一个无效的比较。
				errOp = y
				goto Error
			}

		case !Comparable(x.typ):
			errOp = x
			cause = check.incomparableCause(x.typ)
			goto Error

		case !Comparable(y.typ):
			errOp = y
			cause = check.incomparableCause(y.typ)
			goto Error
		}

	case token.LSS, token.LEQ, token.GTR, token.GEQ:
		// 规范：排序运算符<、<=、>、和>=适用于已排序的操作数。“
		switch {
		case !allOrdered(x.typ):
			errOp = x
			goto Error
		case !allOrdered(y.typ):
			errOp = y
			goto Error
		}

	default:
		unreachable()
	}

	// 比较没问题
	if x.mode == constant_ && y.mode == constant_ {
		x.val = constant.MakeBool(constant.Compare(x.val, op, y.val))
		// 操作数永远不会具体化；不需要更新
		// 它们的类型。
	} else {
		x.mode = value
		// 操作数现在有了它们的最终类型，在运行时-
		// 将具体化。更新表达式树。
		// 如果当前类型是非类型化的，则具体化类型
		// 是相应的默认类型。
		check.updateExprType(x.expr, Default(x.typ), true)
		check.updateExprType(y.expr, Default(y.typ), true)
	}

	// 说明：“比较运算符比较两个操作数并产生
	// 一个非类型化的布尔值。”
	x.typ = Typ[UntypedBool]
	return

Error:
	// 我们有一个操作数错误，可能是错误原因。
	if cause == "" {
		if isTypeParam(x.typ) || isTypeParam(y.typ) {
			// TODO（gri）应报告导致问题的特定类型，如果有任何
			if !isTypeParam(x.typ) {
				errOp = y
			}
			cause = check.sprintf("type parameter %s is not comparable with %s", errOp.typ, op)
		} else {
			cause = check.sprintf("operator %s not defined on %s", op, check.kindString(errOp.typ)) // catch all 
		}
	}
	if switchCase {
		check.errorf(x, code, "invalid case %s in switch on %s (%s)", x.expr, y.expr, cause) // 错误位置始终位于第一个操作数
	} else {
		if compilerErrorMessages {
			check.invalidOp(errOp, code, "%s %s %s (%s)", x.expr, op, y.expr, cause)
		} else {
			check.invalidOp(errOp, code, "cannot compare %s %s %s (%s)", x.expr, op, y.expr, cause)
		}
	}
	x.mode = invalid
}

// ComparableCause返回导致类型不可比的更具体原因。
// 如果没有更具体的原因，结果是“”。
func (check *Checker) incomparableCause(typ Type) string {
	switch under(typ).(type) {
	case *Slice, *Signature, *Map:
		return check.kindString(typ) + " can only be compared to nil"
	}
	// 看看我们能否提取一个更具体的错误
	var cause string
	comparable(typ, true, nil, func(format string, args ...interface{}) {
		cause = check.sprintf(format, args...)
	})
	return cause
}

// kindString将类型kind作为字符串返回。如果e！=nil，它必须是移位表达式；对于非恒定位移，它可能为零。这个函数似乎过于复杂了。重访。
func (check *Checker) kindString(typ Type) string {
	switch under(typ).(type) {
	case *Array:
		return "array"
	case *Slice:
		return "slice"
	case *Struct:
		return "struct"
	case *Pointer:
		return "pointer"
	case *Signature:
		return "func"
	case *Interface:
		if isTypeParam(typ) {
			return check.sprintf("type parameter %s", typ)
		}
		return "interface"
	case *Map:
		return "map"
	case *Chan:
		return "chan"
	default:
	}
}

func (check *Checker) shift(x, y *operand, e ast.Expr, op token.Token) {

	var xval constant.Value
	if x.mode == constant_ {
		xval = constant.ToInt(x.val)
	}

	if allInteger(x.typ) || isUntyped(x.typ) && xval != nil && xval.Kind() == constant.Int {
		// lhs是整数类型或非类型常量，可作为整数表示。无事可做。
	} else {
		// shift没有机会
		check.invalidOp(x, _InvalidShiftOperand, "shifted operand %s must be integer", x)
		x.mode = invalid
		return
	}

	// spec:“shift表达式中的正确操作数必须具有整型
	// 或是可由uint类型的值表示的非类型常量。”

	// 检查常量是否可以用uint表示，但不要将其转换为
	// （另请参见第47243期）。
	if y.mode == constant_ {
		// 为负移位计数提供良好的错误信息。ABCFDG＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊〕
		if yval.Kind() == constant.Int && constant.Sign(yval) < 0 {
			check.invalidOp(y, _InvalidShiftCount, "negative shift count %s", y)
			x.mode = invalid
			return
		}

		if isUntyped(y.typ) {
			check.representable(y, Typ[Uint])
			if y.mode == invalid {
				x.mode = invalid
				return
			}
		}
	} else {
		// 检查RHS是否至少为整数类型。
		switch {
		case allInteger(y.typ):
			if !allUnsigned(y.typ) && !check.allowVersion(check.pkg, 1, 13) {
				check.invalidOp(y, _InvalidShiftCount, "signed shift count %s requires go1.13 or later", y)
				x.mode = invalid
				return
			}
		case isUntyped(y.typ):
			// 这是不正确的，但保留了先前存在的行为。
			// 另请参见错误#47410。
			check.convertUntyped(y, Typ[Uint])
			if y.mode == invalid {
				x.mode = invalid
				return
			}
		default:
			check.invalidOp(y, _InvalidShiftCount, "shift count %s must be integer", y)
			x.mode = invalid
			return
		}
	}

	if x.mode == constant_ {
		if y.mode == constant_ {
			// 如果x或y有未知值，结果未知
			if x.val.Kind() == constant.Unknown || y.val.Kind() == constant.Unknown {
				x.val = constant.MakeUnknown()
				// 确保正确的类型-请参阅下面的注释
				if !isInteger(x.typ) {
					x.typ = Typ[UntypedInt]
				}
				return
			}
			// rhs必须在常量移位的合理范围内
			const shiftBound = 1023 - 1 + 52 // 因此我们可以表示最小的浮点64（请参阅问题#44057）
			s, ok := constant.Uint64Val(y.val)
			if !ok || s > shiftBound {
				check.invalidOp(y, _InvalidShiftCount, "invalid shift count %s", y)
				x.mode = invalid
				return
			}
			// lhs可以表示为整数，但不能表示为整数
			// （例如，2.0，非类型浮点）-这只能发生在非类型
			// 非整数数值常量上。更正类型，使移位
			// 结果为整数类型。
			if !isInteger(x.typ) {
				x.typ = Typ[UntypedInt]
			}
			// x是一个常数，所以xval！=nil，它必须是Int类型的。
			x.val = constant.Shift(xval, op, uint(s))
			x.expr = e
			opPos := x.Pos()
			if b, _ := e.(*ast.BinaryExpr); b != nil {
				opPos = b.OpPos
			}
			check.overflow(x, op, opPos)
			return
		}

		// 带常量lhs的非常量移位
		if isUntyped(x.typ) {
			// 规范：“如果非常量移位
			// 表达式的左操作数是非类型化常量，则
			// 常量的类型与仅用左操作数替换移位表达式
			// 时的类型相同。”。
			// 
			// 延迟操作数检查，直到我们知道最终类型
			// 将lhs表达式标记为lhs移位操作数。
			// 
			// 通常（在正确的程序中），lhs表达式
			// 在非类型映射中。但是，如果同一表达式
			// 被计算两次（通过一个声明周期），则可能会创建错误的程序，例如
			// 在
			// 第一轮中确定lhs表达式类型，从而从映射中删除，然后在第二轮中找不到
			// （重复插入
			// 同一expr节点仍然只会导致
			// 该节点的一个条目，并且只能删除一次）。
			// 小心，检查是否有人进入。
			// 例如：var e，f=int（1<<“”[f]）
			if info, found := check.untyped[x.expr]; found {
				info.isLhs = true
				check.untyped[x.expr] = info
			}
			// 保持x的类型
			x.mode = value
			return
		}
	}

	// 非常量移位-lhs必须是整数
	if !allInteger(x.typ) {
		check.invalidOp(x, _InvalidShiftOperand, "shifted operand %s must be integer", x)
		x.mode = invalid
		return
	}

	x.mode = value
}

var binaryOpPredicates opPredicates

func init() {
	// 在init中设置binaryOpPredicates可以避免声明周期。
	binaryOpPredicates = opPredicates{
		token.ADD: allNumericOrString,
		token.SUB: allNumeric,
		token.MUL: allNumeric,
		token.QUO: allNumeric,
		token.REM: allInteger,

		token.AND:     allInteger,
		token.OR:      allInteger,
		token.XOR:     allInteger,
		token.AND_NOT: allInteger,

		token.LAND: allBoolean,
		token.LOR:  allBoolean,
	}
}

// 如果e！=nil，它必须是二进制表达式；对于非常量表达式
// /（在二进制表达式为隐式的赋值操作中调用时）它可能为零。
func (check *Checker) binary(x *operand, e ast.Expr, lhs, rhs ast.Expr, op token.Token, opPos token.Pos) {
	var y operand

	check.expr(x, lhs)
	check.expr(&y, rhs)

	if x.mode == invalid {
		return
	}
	if y.mode == invalid {
		x.mode = invalid
		x.expr = y.expr
		return
	}

	if isShift(op) {
		check.shift(x, &y, e, op)
		return
	}

	// TODO（gri）make canMix更高效-为每个二进制操作调用
	canMix := func(x, y *operand) bool {
		if IsInterface(x.typ) && !isTypeParam(x.typ) || IsInterface(y.typ) && !isTypeParam(y.typ) {
			return true
		}
		if allBoolean(x.typ) != allBoolean(y.typ) {
			return false
		}
		if allString(x.typ) != allString(y.typ) {
			return false
		}
		if x.isNil() && !hasNil(y.typ) {
			return false
		}
		if y.isNil() && !hasNil(x.typ) {
			return false
		}
		return true
	}
	if canMix(x, &y) {
		check.convertUntyped(x, y.typ)
		if x.mode == invalid {
			return
		}
		check.convertUntyped(&y, x.typ)
		if y.mode == invalid {
			x.mode = invalid
			return
		}
	}

	if isComparison(op) {
		check.comparison(x, &y, op, false)
		return
	}

	if !Identical(x.typ, y.typ) {
		// /只有当我们有有效类型
		// （否则我们已经在其他地方报告了错误）
		if x.typ != Typ[Invalid] && y.typ != Typ[Invalid] {
			var posn positioner = x
			if e != nil {
				posn = e
			}
			if e != nil {
				check.invalidOp(posn, _MismatchedTypes, "%s (mismatched types %s and %s)", e, x.typ, y.typ)
			} else {
				check.invalidOp(posn, _MismatchedTypes, "%s %s= %s (mismatched types %s and %s)", lhs, op, rhs, x.typ, y.typ)
			}
		}
		x.mode = invalid
		return
	}

	if !check.op(binaryOpPredicates, x, op) {
		x.mode = invalid
		return
	}

	if op == token.QUO || op == token.REM {
		// 检查零除数
		if (x.mode == constant_ || allInteger(x.typ)) && y.mode == constant_ && constant.Sign(y.val) == 0 {
			check.invalidOp(&y, _DivByZero, "division by zero")
			x.mode = invalid
			return
		}

		// 检查复数除法中的除数不足（参见20227期）
		if x.mode == constant_ && y.mode == constant_ && isComplex(x.typ) {
			re, im := constant.Real(y.val), constant.Imag(y.val)
			re2, im2 := constant.BinaryOp(re, token.MUL, re), constant.BinaryOp(im, token.MUL, im)
			if constant.Sign(re2) == 0 && constant.Sign(im2) == 0 {
				check.invalidOp(&y, _DivByZero, "division by zero")
				x.mode = invalid
				return
			}
		}
	}

	if x.mode == constant_ && y.mode == constant_ {
		// 如果x或y有未知值，则结果为未知
		if x.val.Kind() == constant.Unknown || y.val.Kind() == constant.Unknown {
			x.val = constant.MakeUnknown()
			// x.typ不变
			return
		}
		// force整型操作数的整除
		if op == token.QUO && isInteger(x.typ) {
			op = token.QUO_ASSIGN
		}
		x.val = constant.BinaryOp(x.val, op, y.val)
		x.expr = e
		check.overflow(x, op, opPos)
		return
	}

	x.mode = value
	// x.typ未更改
}

// exprKind描述表达式的类型；
// 类型决定表达式在“语句上下文”中是否有效。
type exprKind int

const (
	conversion exprKind = iota
	expression
	statement
)

// rawExpr类型检查表达式e，并用表达式
// 值或类型初始化x。如果发生错误，x.mode将设置为无效。
// 如果提示！=nil，它是复合文字元素的类型。
// 如果设置了allowGeneric，则操作数类型可能是未实例化的
// 参数化类型或函数值。
// 
func (check *Checker) rawExpr(x *operand, e ast.Expr, hint Type, allowGeneric bool) exprKind {
	if trace {
		check.trace(e.Pos(), "expr %s", e)
		check.indent++
		defer func() {
			check.indent--
			check.trace(e.Pos(), "=> %s", x)
		}()
	}

	kind := check.exprInternal(x, e, hint)

	if !allowGeneric {
		check.nonGeneric(x)
	}

	check.record(x)

	return kind
}

// 如果x是泛型函数或类型，非泛型将报告错误并使x.mode和x.typ无效。
// 否则它只剩下x。
func (check *Checker) nonGeneric(x *operand) {
	if x.mode == invalid || x.mode == novalue {
		return
	}
	var what string
	switch t := x.typ.(type) {
	case *Named:
		if isGeneric(t) {
			what = "type"
		}
	case *Signature:
		if t.tparams != nil {
			what = "function"
		}
	}
	if what != "" {
		check.errorf(x.expr, _WrongTypeArgCount, "cannot use generic %s %s without instantiation", what, x.expr)
		x.mode = invalid
		x.typ = Typ[Invalid]
	}
}

// exprInternal包含表达式类型检查的核心。
// 只能由rawExpr调用。
// 
func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
	// 确保x在紧急情况下具有有效状态
	// （was问题5770）
	x.mode = invalid
	x.typ = Typ[Invalid]

	switch e := e.(type) {
	case *ast.BadExpr:
		goto Error // 在

	case *ast.Ident:
		check.ident(x, e, nil, false)

	case *ast.Ellipsis:
		// 之前报告了错误
		// 在合法的情况下显式处理省略号
		// （数组复合文字和参数列表）
		check.error(e, _BadDotDotDotSyntax, "invalid use of '...'")
		goto Error

	case *ast.BasicLit:
		switch e.Kind {
		case token.INT, token.FLOAT, token.IMAG:
			check.langCompat(e)
			// 非类型数字的最大尾数精度值
			// 是512位，或两个整数
			// 中的每一个都是4048位，这是在go/常量包中准确表示的浮点数的小数部分。
			// 比这许多位长的常量文本
			// 没有意义；过长的常数可能会消耗大量的空间和时间进行无用的转换。
			// 为常量长度加上一个宽大的上限，该上限也允许在所有数字之间使用分隔符。
			const limit = 10000
			if len(e.Value) > limit {
				check.errorf(e, _InvalidConstVal, "excessively long constant: %s... (%d chars)", e.Value[:10], len(e.Value))
				goto Error
			}
		}
		x.setConst(e.Kind, e.Value)
		if x.mode == invalid {
			// 解析器已经建立了语法正确性。
			// 如果我们到了这里，那是因为-/溢出下的数字。
			// TODO（gri）setConst（以及go/constant包）
			// 应该返回一个描述问题的错误。
			check.errorf(e, _InvalidConstVal, "malformed constant: %s", e.Value)
			goto Error
		}

	case *ast.FuncLit:
		if sig, ok := check.typ(e.Type).(*Signature); ok {
			if !check.conf.IgnoreFuncBodies && e.Body != nil {
				// 匿名函数被认为是
				// 包含
				// 的init expression/func声明的一部分：使用现有的包级声明信息。
				decl := check.decl // 捕获用于下面的闭包
				iota := check.iota // 捕获用于下面的闭包（#22345）
				// 不要立即进行类型检查，因为函数可能是
				// 函数体引用的类型定义的一部分。相反，请尽快键入check，
				// 但在封闭范围内容更改之前（#22992）。
				check.later(func() {
					check.funcBody(decl, "<function literal>", sig, e.Body, iota)
				})
			}
			x.mode = value
			x.typ = sig
		} else {
			check.invalidAST(e, "invalid function literal %s", e)
			goto Error
		}

	case *ast.CompositeLit:
		var typ, base Type

		switch {
		case e.Type != nil:
			// 复合文字类型存在-使用它
			// /[…]T数组类型只能与复合文字一起出现。
			// 在这里检查一下，这样我们就不必处理。。。一般来说
			if atyp, _ := e.Type.(*ast.ArrayType); atyp != nil && atyp.Len != nil {
				if ellip, _ := atyp.Len.(*ast.Ellipsis); ellip != nil && ellip.Elt == nil {
					// 我们有一个“开放”[…]T数组类型。
					// 创建长度未知的新ArrayType（-1）
					// 并在分析文本后完成设置。
					typ = &Array{len: -1, elem: check.varType(atyp.Elt)}
					base = typ
					break
				}
			}
			typ = check.typ(e.Type)
			base = typ

		case hint != nil:
			// 不存在复合文字类型-使用提示（封闭类型的元素类型）
			typ = hint
			base, _ = deref(coreType(typ)) // /*T implies&T{}
			if base == nil {
				check.errorf(e, _InvalidLit, "invalid composite literal element type %s: no core type", typ)
				goto Error
			}

		default:
			// TODO（gri）根据上下文提供更好的错误消息
			check.error(e, _UntypedLit, "missing type in composite literal")
			goto Error
		}

		switch utyp := coreType(base).(type) {
		case *Struct:
			// 如果尚未设置引用的结构，则防止崩溃。
			// 请参见*数组的类似注释。
			if utyp.fields == nil {
				check.error(e, _InvalidDeclCycle, "illegal cycle in type declaration")
				goto Error
			}
			if len(e.Elts) == 0 {
				break
			}
			fields := utyp.fields
			if _, ok := e.Elts[0].(*ast.KeyValueExpr); ok {
				// 所有元素必须有密钥
				visited := make([]bool, len(fields))
				for _, e := range e.Elts {
					kv, _ := e.(*ast.KeyValueExpr)
					if kv == nil {
						check.error(e, _MixedStructLit, "mixture of field:value and value elements in struct literal")
						continue
					}
					key, _ := kv.Key.(*ast.Ident)
					// 尽早（在由于错误退出之前）进行所有可能的检查
					// 因此我们不会将信息放在地板上
					check.expr(x, kv.Value)
					if key == nil {
						check.errorf(kv, _InvalidLitField, "invalid field name %s in struct literal", kv.Key)
						continue
					}
					i := fieldIndex(utyp.fields, check.pkg, key.Name)
					if i < 0 {
						check.errorf(kv, _MissingLitField, "unknown field %s in struct literal", key.Name)
						continue
					}
					fld := fields[i]
					check.recordUse(key, fld)
					etyp := fld.typ
					check.assignment(x, etyp, "struct literal")
					// 0<=i<len（字段）
					if visited[i] {
						check.errorf(kv, _DuplicateLitField, "duplicate field name %s in struct literal", key.Name)
						continue
					}
					visited[i] = true
				}
			} else {
				// 任何元素都不必须有密钥
				for i, e := range e.Elts {
					if kv, _ := e.(*ast.KeyValueExpr); kv != nil {
						check.error(kv, _MixedStructLit, "mixture of field:value and value elements in struct literal")
						continue
					}
					check.expr(x, e)
					if i >= len(fields) {
						check.error(x, _InvalidStructLit, "too many values in struct literal")
						break // 无法继续
					}
					// 我<len（字段）
					fld := fields[i]
					if !fld.Exported() && fld.pkg != check.pkg {
						check.errorf(x,
							_UnexportedLitField,
							"implicit assignment to unexported field %s in %s literal", fld.name, typ)
						continue
					}
					etyp := fld.typ
					check.assignment(x, etyp, "struct literal")
				}
				if len(e.Elts) < len(fields) {
					check.error(inNode(e, e.Rbrace), _InvalidStructLit, "too few values in struct literal")
					// 确定继续
				}
			}

		case *Array:
			// 如果尚未设置所指的阵列，请防止崩溃。这是第18643号问题。
			// 这是权宜之计。应该使用Checker。objPath报告整个
			// 从源代码中最早声明开始的路径。TODO（gri）解决这个问题。
			if utyp.elem == nil {
				check.error(e, _InvalidTypeCycle, "illegal cycle in type declaration")
				goto Error
			}
			n := check.indexedElts(e.Elts, utyp.elem, utyp.len)
			// 如果我们有一个长度未知的数组（通常是[…]T数组，也可以是
			// 数组[n]T，其中n无效）现在就设置长度，并且
			// 记录数组的类型（通常通过check.typ完成，它不是
			// 调用的[…]T） 。我们处理[…]T数组和带有无效
			// 长度的数组在这里是相同的，因为如果我们有一个复合文字，可以“猜测”
			// 的长度；e、 g.对于[n]int{1,2,3}
			// 当n因某种原因无效时，可以公平地假设它应该
			// be 3（另请参见Checked.arrayLength和issue#27346）。
			if utyp.len < 0 {
				utyp.len = n
				// e.如果我们有一个复合文字元素
				// 它本身就是一个省略了类型的复合文字，那么Type就丢失了。在
				// 这种情况下，没有要记录的内容（
				// 中没有该点的源类型）。
				if e.Type != nil {
					check.recordTypeAndValue(e.Type, typexpr, utyp, nil)
				}
			}

		case *Slice:
			// 如果所指的切片尚未设置，则防止崩溃。
			// 请参见*数组的类似注释。
			if utyp.elem == nil {
				check.error(e, _InvalidTypeCycle, "illegal cycle in type declaration")
				goto Error
			}
			check.indexedElts(e.Elts, utyp.elem, -1)

		case *Map:
			// 如果所指的地图尚未设置，请防止崩溃。
			// 请参见*数组的类似注释。
			if utyp.key == nil || utyp.elem == nil {
				check.error(e, _InvalidTypeCycle, "illegal cycle in type declaration")
				goto Error
			}
			visited := make(map[any][]Type, len(e.Elts))
			for _, e := range e.Elts {
				kv, _ := e.(*ast.KeyValueExpr)
				if kv == nil {
					check.error(e, _MissingLitKey, "missing key in map literal")
					continue
				}
				check.exprWithHint(x, kv.Key, utyp.key)
				check.assignment(x, utyp.key, "map literal")
				if x.mode == invalid {
					continue
				}
				if x.mode == constant_ {
					duplicate := false
					// 如果键是接口类型，那么在检查重复项时，该类型也很重要
					xkey := keyVal(x.val)
					if IsInterface(utyp.key) {
						for _, vtyp := range visited[xkey] {
							if Identical(vtyp, x.typ) {
								duplicate = true
								break
							}
						}
						visited[xkey] = append(visited[xkey], x.typ)
					} else {
						_, duplicate = visited[xkey]
						visited[xkey] = nil
					}
					if duplicate {
						check.errorf(x, _DuplicateLitKey, "duplicate key %s in map literal", x.val)
						continue
					}
				}
				check.exprWithHint(x, kv.Value, utyp.elem)
				check.assignment(x, utyp.elem, "map literal")
			}

		default:
			// 当“使用”所有元素时，解包KeyValueExpr 
			// 因为检查而显式。use不接受它们
			for _, e := range e.Elts {
				if kv, _ := e.(*ast.KeyValueExpr); kv != nil {
					// 理想情况下，我们也应该“使用”kv。但是我们不能知道
					// 它是否是一个外部定义的结构键。无论如何向前走可能会导致其他错误。放弃吧。
					e = kv.Value
				}
				check.use(e)
			}
			// 如果utyp无效，则在
			if utyp != Typ[Invalid] {
				check.errorf(e, _InvalidLit, "invalid composite literal type %s", typ)
				goto Error
			}
		}

		x.mode = value
		x.typ = typ

	case *ast.ParenExpr:
		kind := check.rawExpr(x, e.X, nil, false)
		x.expr = e
		return kind

	case *ast.SelectorExpr:
		check.selector(x, e, nil)

	case *ast.IndexExpr, *ast.IndexListExpr:
		ix := typeparams.UnpackIndexExpr(e)
		if check.indexExpr(x, ix) {
			check.funcInst(x, ix)
		}
		if x.mode == invalid {
			goto Error
		}

	case *ast.SliceExpr:
		check.sliceExpr(x, e)
		if x.mode == invalid {
			goto Error
		}

	case *ast.TypeAssertExpr:
		check.expr(x, e.X)
		if x.mode == invalid {
			goto Error
		}
		// TODO（gri）之前报告了一个错误。我们可能希望允许在某个时间点对类型参数值进行类型断言
		if isTypeParam(x.typ) {
			check.invalidOp(x, _InvalidAssert, "cannot use type assertion on type parameter value %s", x)
			goto Error
		}
		if _, ok := under(x.typ).(*Interface); !ok {
			check.invalidOp(x, _InvalidAssert, "%s is not an interface", x)
			goto Error
		}
		// x。（类型）表达式在类型开关
		if e.Type == nil {
			// 不要使用invalidAST，因为这可能发生在
			// go/parser生成的AST中。
			check.error(e, _BadTypeKeyword, "use of .(type) outside type switch")
			goto Error
		}
		T := check.varType(e.Type)
		if T == Typ[Invalid] {
			goto Error
		}
		check.typeAssertion(e, x, T, false)
		x.mode = commaok
		x.typ = T

	case *ast.CallExpr:
		return check.callExpr(x, e)

	case *ast.StarExpr:
		check.exprOrType(x, e.X, false)
		switch x.mode {
		case invalid:
			goto Error
		case typexpr:
			check.validVarType(e.X, x.typ)
			x.typ = &Pointer{base: x.typ}
		default:
			var base Type
			if !underIs(x.typ, func(u Type) bool {
				p, _ := u.(*Pointer)
				if p == nil {
					check.invalidOp(x, _InvalidIndirection, "cannot indirect %s", x)
					return false
				}
				if base != nil && !Identical(p.base, base) {
					check.invalidOp(x, _InvalidIndirection, "pointers of %s must have identical base types", x)
					return false
				}
				base = p.base
				return true
			}) {
				goto Error
			}
			x.mode = variable
			x.typ = base
		}

	case *ast.UnaryExpr:
		check.unary(x, e)
		if x.mode == invalid {
			goto Error
		}
		if e.Op == token.ARROW {
			x.expr = e
			return statement // 接收操作可能出现在语句上下文中
		}

	case *ast.BinaryExpr:
		check.binary(x, e, e.X, e.Y, e.Op, e.OpPos)
		if x.mode == invalid {
			goto Error
		}

	case *ast.KeyValueExpr:
		// 键：值表达式以复合文字处理
		check.invalidAST(e, "no key:value expected")
		goto Error

	case *ast.ArrayType, *ast.StructType, *ast.FuncType,
		*ast.InterfaceType, *ast.MapType, *ast.ChanType:
		x.mode = typexpr
		x.typ = check.typ(e)
		// 注意：rawExpr（exprInternal的调用者）将调用check。记录类型和值
		// 即使检查。typ已经给它打过电话了。这很好，因为两个
		// 都记录了相同的表达式和类型。这也不是一个
		// 性能问题，因为我们这里只讨论复合文字
		// 类型，这是相对罕见的。

	default:
		panic(fmt.Sprintf("%s: unknown expression type %T", check.fset.Position(e.Pos()), e))
	}

	// 一切顺利
	x.expr = e
	return expression

Error:
	x.mode = invalid
	x.expr = e
	return statement // 避免后续错误
}

func keyVal(x constant.Value) any {
	switch x.Kind() {
	case constant.Bool:
		return constant.BoolVal(x)
	case constant.String:
		return constant.StringVal(x)
	case constant.Int:
		if v, ok := constant.Int64Val(x); ok {
			return v
		}
		if v, ok := constant.Uint64Val(x); ok {
			return v
		}
	case constant.Float:
		v, _ := constant.Float64Val(x)
		return v
	case constant.Complex:
		r, _ := constant.Float64Val(constant.Real(x))
		i, _ := constant.Float64Val(constant.Imag(x))
		return complex(r, i)
	}
	return x
}

// 类型断言检查x.（T）。x的类型必须是接口。
func (check *Checker) typeAssertion(e ast.Expr, x *operand, T Type, typeSwitch bool) {
	method, alt := check.assertableTo(under(x.typ).(*Interface), T)
	if method == nil {
		return // 成功
	}

	cause := check.missingMethodReason(T, x.typ, method, alt)

	if typeSwitch {
		check.errorf(e, _ImpossibleAssert, "impossible type switch case: %s\n\t%s cannot have dynamic type %s %s", e, x, T, cause)
		return
	}

	check.errorf(e, _ImpossibleAssert, "impossible type assertion: %s\n\t%s does not implement %s %s", e, T, x.typ, cause)
}

// expr类型检查表达式e并用表达式值初始化x。
// 结果必须是单个值。
// 如果发生错误，x.mode将设置为无效。
// 
func (check *Checker) expr(x *operand, e ast.Expr) {
	check.rawExpr(x, e, nil, false)
	check.exclude(x, 1<<novalue|1<<builtin|1<<typexpr)
	check.singleValue(x)
}

// multiExpr与expr类似，但结果也可能是一个多值。
func (check *Checker) multiExpr(x *operand, e ast.Expr) {
	check.rawExpr(x, e, nil, false)
	check.exclude(x, 1<<novalue|1<<builtin|1<<typexpr)
}

// exprWithHint类型检查表达式e，并用表达式值初始化x；
// 提示是复合文字元素的类型。
// 如果发生错误，x.mode将设置为无效。
// 
func (check *Checker) exprWithHint(x *operand, e ast.Expr, hint Type) {
	assert(hint != nil)
	check.rawExpr(x, e, hint, false)
	check.exclude(x, 1<<novalue|1<<builtin|1<<typexpr)
	check.singleValue(x)
}

// exprOrType类型检查表达式或类型e，并用表达式值或类型初始化x。
// 如果设置了allowGeneric，则操作数类型可能是未实例化的参数化类型或函数
// 值。
// 如果发生错误，x.mode将设置为无效。
// 
func (check *Checker) exprOrType(x *operand, e ast.Expr, allowGeneric bool) {
	check.rawExpr(x, e, nil, allowGeneric)
	check.exclude(x, 1<<novalue)
	check.singleValue(x)
}

// exclude在x.mode处于modeset并将x.mode设置为无效时报告错误。
// 该模式集可以包含以下任何一项：。
func (check *Checker) exclude(x *operand, modeset uint) {
	if modeset&(1<<x.mode) != 0 {
		var msg string
		var code errorCode
		switch x.mode {
		case novalue:
			if modeset&(1<<typexpr) != 0 {
				msg = "%s used as value"
			} else {
				msg = "%s used as value or type"
			}
			code = _TooManyValues
		case builtin:
			msg = "%s must be called"
			code = _UncalledBuiltin
		case typexpr:
			msg = "%s is not an expression"
			code = _NotAnExpr
		default:
			unreachable()
		}
		check.errorf(x, code, msg, x)
		x.mode = invalid
	}
}

// 如果x描述元组并将x.mode设置为无效，singleValue将报告错误。
func (check *Checker) singleValue(x *operand) {
	if x.mode == value {
		// 元组类型从未命名-不需要在
		if t, ok := x.typ.(*Tuple); ok {
			assert(t.Len() != 1)
			if compilerErrorMessages {
				check.errorf(x, _TooManyValues, "multiple-value %s in single-value context", x)
			} else {
				check.errorf(x, _TooManyValues, "%d-valued %s where single value is expected", t.Len(), x)
			}
			x.mode = invalid
		}
	}
}
